package com.ucpaas.sms.util;

import com.hankcs.hanlp.HanLP;
import com.jsmsframework.audit.entity.JsmsAuditKeywordCategory;
import com.jsmsframework.audit.util.DFAUtil4AuditUtil;
import com.jsmsframework.common.util.DFAUtil;
import com.jsmsframework.common.util.JsonUtil;
import com.ucpaas.sms.model.KeywordMatchTuple;
import com.ucpaas.sms.model.KeywordMatchTupleCategory;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * 关键字匹配工具类（基于DFA实现）
 */

public class KeyWrodSearchUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(KeyWrodSearchUtils.class);

    /**
     * 构建用于实现关键字检索的Map
     * @param keywordList
     * @return
     */
    public static Map<String, Object> builWorldMap(List<String> keywordList){
        long start = System.currentTimeMillis();
        Map<String, Object> sesitiveWrodRootMap = new HashMap<>(keywordList.size());
        Map<String, Object> fatherMap;
        Map<String, Object> childMap;

        Iterator<String> iterator = keywordList.iterator();
        fatherMap = sesitiveWrodRootMap;
        while (iterator.hasNext()) {
            String keyword = iterator.next();
//            keyword = HanLP.convertToSimplifiedChinese(keyword);
            keyword = JsmsHanLPUtils.convertToSimplifiedChinese(keyword);
            for (int pos = 0; pos < keyword.length(); pos ++) {
                char kwChar = keyword.charAt(pos);
                Object obj = fatherMap.get(String.valueOf(kwChar));
                if(obj != null) {
                    fatherMap = (Map) obj;
                } else {
                    childMap = new HashMap<>();
                    fatherMap.put(String.valueOf(kwChar), childMap) ;
                    fatherMap = childMap;
                }
            }
            fatherMap.put("end", true);
            fatherMap = sesitiveWrodRootMap;
        }

        LOGGER.debug("KeyWrodSearchUtils.builWorldMap 耗时{}ms", System.currentTimeMillis() - start);
        return sesitiveWrodRootMap;
    }

    /**
     * 匹配keywordList中所有关键字content这个文本中的开始和结束位置
     * @param content 文本
     * @param sesitiveWrodRootMap 由KeyWrodSearchUtils.builWorldMap生成
     * @return 返回被匹配到的关键字及它在文本中的起始位置
     */
    public static List<KeywordMatchTuple<String, Integer, Integer>> searchKeywordPosByWorldMap(String content, Map<String, Object> sesitiveWrodRootMap) {
        long start = System.currentTimeMillis();

        List<KeywordMatchTuple<String, Integer, Integer>> resultList = new ArrayList<>();
        Map<String, Object> treeMap = null;
        boolean match = false; //
        StringBuilder matchSb = null;
        String key = null;
        int pEnd = 0;

        for (int pStar = 0; pStar < content.length(); pStar++) {
            treeMap = sesitiveWrodRootMap; // 回溯到根部
            pEnd = pStar;
            matchSb = new StringBuilder();
            match = false;
            while(true) {
                if(pEnd == content.length()){
                    break; //已经检查到文本的最后
                }
                key = String.valueOf(content.charAt(pEnd));
                Object obj = treeMap.get(key);
                if(obj == null){
                    break; // 本次匹配结束
                }else{
                    treeMap = (Map<String, Object>) obj;
                    matchSb.append(key);
                }
                pEnd++;
                obj = treeMap.get("end"); // 关键字最长匹配原则
                if(obj != null) {
                    match = true;
                }
            }

            // 是否匹配到关键字
            if(match) {
                resultList.add(new KeywordMatchTuple<>(matchSb.toString(), pStar, pEnd));
                pStar = pEnd-1;   //是有用的，因为for循环pStart++了
            }
        }

        LOGGER.debug("KeyWrodSearchUtils.searchKeywordPosByWorldMap 耗时{}ms", System.currentTimeMillis() - start);
        return resultList;
    }







    /**
     * 匹配keywordList中所有关键字content这个文本中的开始和结束位置
     * @param content 文本
     * @param sesitiveWrodRootMap 由KeyWrodSearchUtils.builWorldMap生成
     * @return 返回被匹配到的关键字及它在文本中的起始位置
     */
    public static List<KeywordMatchTuple<String, Integer, Integer>> searchKeywordPosByWorldMapSkipBlank(String content, Map<String, Object> sesitiveWrodRootMap) {
        long start = System.currentTimeMillis();
        if(content!=null){
            content = content.toLowerCase();
//            content = HanLP.convertToSimplifiedChinese(content); //繁体转简体
            content = JsmsHanLPUtils.convertToSimplifiedChinese(content); //繁体转简体
        }

        List<KeywordMatchTuple<String, Integer, Integer>> resultList = new ArrayList<>();
        Map<String, Object> treeMap = null;
        boolean match = false; //
        StringBuilder matchSb = null;
        String key = null;
        int pEnd = 0;

        for (int pStar = 0; pStar < content.length(); pStar++) {
            treeMap = sesitiveWrodRootMap; // 回溯到根部
            pEnd = pStar;
            matchSb = new StringBuilder();
            match = false;
            while(true) {
                if(pEnd == content.length()){
                    pEnd++;
                    break; //已经检查到文本的最后
                }
                key = String.valueOf(content.charAt(pEnd));
                pEnd++;

                if(StringUtils.isNotBlank(key)) {
                    Object obj = treeMap.get(key);
                    if (obj == null) {
                        break; // 本次匹配结束
                    } else {
                        treeMap = (Map<String, Object>) obj;
                        matchSb.append(key);
                    }
                    obj = treeMap.get("end"); // 关键字最长匹配原则
                    if (obj != null) {
                        match = true;
                    }
                }
            }

            // 是否匹配到关键字
            if(match) {
                --pEnd;
                resultList.add(new KeywordMatchTuple<>(matchSb.toString(), pStar, pEnd));
                pStar = pEnd;
                pStar--;
            }
        }

        LOGGER.debug("KeyWrodSearchUtils.searchKeywordPosByWorldMap 耗时{}ms", System.currentTimeMillis() - start);
        return resultList;
    }


    public static void main(String[] args) {
        System.out.println(HanLP.convertToTraditionalChinese("用笔记本电脑写程序")+"aaa");
        System.out.println(JsmsHanLPUtils.convertToTraditionalChinese("用笔记本电脑写程序")+"aaa");
        System.out.println(HanLP.convertToSimplifiedChinese("「以後等妳當上皇后，就能買士多啤梨慶祝了」")+"aaa");
        System.out.println(JsmsHanLPUtils.convertToSimplifiedChinese("「以後等妳當上皇后，就能買士多啤梨慶祝了」")+"aaa");
        System.out.println(HanLP.convertToSimplifiedChinese("「以後等妳當上皇后，就能買士多啤梨慶祝了」")+"aaa");
        System.out.println(JsmsHanLPUtils.convertToSimplifiedChinese("按時到福建省的會計法愛上的回復1附件是逗你放假拍攝的及覅是奇偶計費abdafasABDADFASD".toLowerCase())+"aaa");
        String str = "按時到福建省的會計法愛上的回復1附件是逗你放假拍攝的及覅是奇偶計費abdafasABDADFASD";
        long s = System.currentTimeMillis();
        /*for (int i = 0; i < 100000; i++) {
            testConvert();
        }*/
        long e = System.currentTimeMillis();
        System.out.println("耗时--->"+ (e-s));

    }

    private static void testConvert(){
        String content = "您的运单668252748590,您的快件已到南校代理点，自提地址：万山路（北华南校与29中学交汇）东走200米天天快递，收到短信尽快取件，逾期退回。学生到店发件享8折优惠";
//        System.out.println(HanLP.convertToSimplifiedChinese(content.toLowerCase())+"aaa");
        JsmsHanLPUtils.convertToSimplifiedChinese(content);
//        System.out.println(sb.toString());
    }


    public static List<KeywordMatchTupleCategory<String,Integer,Integer,JsmsAuditKeywordCategory>> searchKeywordPosByDFATreeSkipBlank(String content, DFAUtil4AuditUtil.DFANode4Audit<String> dfaTree) {

        List<KeywordMatchTupleCategory<String, Integer, Integer,JsmsAuditKeywordCategory>> resultList = new ArrayList<>();
        try {
            long start = System.currentTimeMillis();
            if(dfaTree.isEnd())
                return resultList;

            /*if(content!=null){
                content = content.toLowerCase();
                content = HanLP.convertToSimplifiedChinese(content); //繁体转简体
            }*/

            if(content!=null){
                String orginContent = content;
                content = content.toLowerCase();
                /*StringBuilder sb = new StringBuilder();
                for (int i = 0; i < content.length(); i++) {
                    sb.append(HanLP.convertToSimplifiedChinese(String.valueOf(content.charAt(i))));
                }
                content = sb.toString(); */
                content = JsmsHanLPUtils.convertToSimplifiedChinese(content);//繁体转简体
                if(orginContent!=null&&orginContent.length()!=content.length()){
                    LOGGER.info("简繁体工具转换异常, 原长度={}, 转后长度={}, 原内容={}, 转后内容={}",orginContent.length(),content.length(),orginContent,content);
                    return resultList;
                }

            }

            DFAUtil.DFANode<String> treeMap = null;
            boolean match = false; //
    //        StringBuilder matchSb = null;
            StringBuilder matchSb = new StringBuilder();
            String key = null;
            int pEnd = 0;

            for (int pStar = 0; pStar < content.length(); pStar++) {
                treeMap = dfaTree; // 回溯到根部
                pEnd = pStar;
    //            matchSb = new StringBuilder();
                matchSb.delete(0,matchSb.length());
                match = false;
                JsmsAuditKeywordCategory category = null;
                while(true) {
                    if(pEnd == content.length()){
                        pEnd++;
                        break; //已经检查到文本的最后
                    }
                    key = String.valueOf(content.charAt(pEnd));
                    pEnd++;
                    if(StringUtils.isNotBlank(key)) {
                        DFAUtil.DFANode<String> obj = treeMap.get(key);
                        if (obj == null) {
                            break; // 本次匹配结束
                        } else {
    //                        if(category==null)
                            category = ((DFAUtil4AuditUtil.DFANode4Audit<String>)obj).getCategory();
                            treeMap =  obj;
                            matchSb.append(key);
                        }
                        if (treeMap.isEnd()) {
                            match = true;
                        }
                    }
                }

                // 是否匹配到关键字
                if(match) {
                    --pEnd;
                    resultList.add(new KeywordMatchTupleCategory<>(matchSb.toString(), pStar, pEnd,category));
                    pStar = pEnd - 1; //因为for循环有pStar++
                }
            }

            LOGGER.debug("KeyWrodSearchUtils.searchKeywordPosByDFATreeSkipBlank 耗时{}ms", System.currentTimeMillis() - start);

        }catch (Exception e){
            LOGGER.info("简繁体工具转换异常,audit={}", JsonUtil.toJson(content));
            return resultList;
        }
        return resultList;

    }
}
